
#ifndef SORTFUN5_H
#define SORTFUN5_H
#include <string>
#include <iostream>

#include <algorithm>
#include <functional>
#include <vector>
#include <map>
#include "ProtoFile.h"
#include "Disktools.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fstream>
#include "buffclass.h"
#include "bt_mutex.h"
#include "bt_thread.h"
#include "saft_deque.h"
#include "sndaconfig.h"

struct splittxtfilearg
{
        std::string srcfile;
        std::string dirs;
        std::vector<ReadProtoFile *> * filelist;
        long long splitsize;
};

extern mutex_block split_lock;
extern int needsplit;
extern int splited;
extern saft_deque<splittxtfilearg> request_splittxtfilearg;

const int printline = 10000;

void * SlipTxtThread(void *);

template<class T, class Tless>
void SortTab5(std::multimap<T *, long, Tless> &m_sorttab, std::string &dirs
        , std::string & filename, std::vector<ReadProtoFile *> &filelist)
{
    time_t tnow = time(0);
    time_t tnow2 = time(0);
    
    long vvv = 0;
    std::string destfilename = dirs + filename;
    std::string srcfilename = dirs + filename;
    std::cout << "begin SortTab5 " << time(0) << " " << time(0) - tnow
            << std::endl;
    {
        WriteProtoFile WpDestfile(destfilename);
        
        for(typename std::multimap<T *, long, Tless>::iterator recpos =
                m_sorttab.begin(); recpos != m_sorttab.end(); ++recpos)
        {
            WpDestfile.SaveProject(*(recpos->first));
            
            delete (recpos->first);
            ++vvv;
            
            if(vvv % printline == 0)
            {
                std::cout << " SortTab5 for " << vvv << "  " << time(0) - tnow2
                        << std::endl;
                tnow2 = time(0);
            }
            
        }
        
        m_sorttab.clear();
    }
    ReadProtoFile *preadfile = new ReadProtoFile(destfilename);
    split_lock.lock();
    filelist.push_back(preadfile);
    split_lock.unlock();
    
    std::cout << "push " << filelist.size() << std::endl;
    std::cout << "end SortTab5 " << time(0) << " " << time(0) - tnow
            << std::endl;
    
}

template<class T, class Tless>
void SplitTxtFile5(std::string &srcfile, std::string dirs,
        std::vector<ReadProtoFile *> & filelist, int splitsize)
{
    std::string filename;
    static int indexid = 0;
    
    char buff[txtBuffLen] = { 0 };
    char filenamebuff[1024] = { 0 };
    FILE * fp = fopen(srcfile.c_str(), "rb");
    
    std::multimap<T *, long, Tless> *m_sorttab = new std::multimap<T *, long,
            Tless>;
    bool finished;
    std::cout << "begin read " << std::endl;
    
    BuffClass Buffer;
    bool fileend = false;
    while(1)
    {
        long long canreadlen = Buffer.CanAddBufflen();
        
        long long readedlen = fread(Buffer.GetBuff(), 1, canreadlen, fp);
        
        if(readedlen == 0)
        {
            fileend = true;
        }
        Buffer.AddUsedData(readedlen);
        long long v = 0;
        
        for(;;)
        {
            char * ppoint = NULL;
            ppoint = Buffer.GetLine();
            
            if(ppoint)
            {
                ++v;
                //std::cout << v << " "  << std::endl;
                
                T *tmpt1 = new T();
                ReadkeybaserecordFromBuff(ppoint, *tmpt1);
                
                (*m_sorttab).insert(std::make_pair(tmpt1, 0));
                
                if((*m_sorttab).size() >= splitsize)
                {
                    split_lock.lock();
                    sprintf(filenamebuff, "%ld.tmp", ++indexid);
                    filename = filenamebuff;
                    split_lock.unlock();
                    std::cout << "read " << std::endl;
                    SortTab5<T, Tless>((*m_sorttab), dirs, filename, filelist);
                    std::cout << "begin read " << std::endl;
                }
            }
            else  // no enough data
            {
                Buffer.ClearUsedbuff();
                break;
            }
        }
        if(fileend == true)
        {
            break;
        }
        
    }
    split_lock.lock();
    
    sprintf(filenamebuff, "%ld.tmp", ++indexid);
    filename = filenamebuff;
    split_lock.unlock();
    
    std::cout << "read " << std::endl;
    
    SortTab5<T, Tless>((*m_sorttab), dirs, filename, filelist);
    
    fclose(fp);
    delete m_sorttab;
}

template<class T, class Tless>
void SumSort5(std::string &destfilename, std::vector<ReadProtoFile *> &filelist)
{
    WriteProtoFile WpDestfile(destfilename);
    std::multimap<T *, long long, Tless> m_sorttab;
    
    long long x = 0;
    for(typename std::vector<ReadProtoFile *>::iterator pos = filelist.begin();
            pos != filelist.end(); ++pos)
            {
        T *tmpt1 = new T();
        std::cout << *pos << "  " << tmpt1 << std::endl;
        
        (*pos)->GetProject(*tmpt1);
        
        m_sorttab.insert(std::make_pair(tmpt1, x));
        ++x;
    }

    std::cout << " begin for" << std::endl;
    for(;;)
    {
        if(m_sorttab.size() == 0)
        {
            break;
        }

        typename std::multimap<T *, long long, Tless>::iterator pos2 =
                m_sorttab.begin();
        
        //std::cout << " begin save " << std::endl;
        // save the lessest object
        WpDestfile.SaveProject(*(pos2->first));
        //std::cout << " begin delete " << std::endl;
        
        //std::cout << " end delete " << std::endl;
        
        // get index key
        long long index = pos2->second;
        T *pa = pos2->first;
        m_sorttab.erase(pos2);
        delete pa;
        //std::cout << " end erase " << std::endl;
        T *tmpt1 = new T();
        
        if(filelist[index]->GetProject(*tmpt1))
        {
            m_sorttab.insert(std::make_pair(tmpt1, index));
        }
        else
        {
            delete tmpt1;
        }
    }
    
}

template<class T, class Tless>
void SortTxtFile5(std::string disk, std::string destfile,
        int splipsize = 50 * 10 * 1024, std::string tempdir = "")
{
    std::vector<ReadProtoFile *> filelist;
    char buff[1024] = { 0 };
    if(tempdir == "")
    {
        sprintf(buff, "./temp/%lld_%ld/", time(NULL), rand());
    }
    else
    {
        sprintf(buff, "./temp/mytemp/%s/%lld_%lld/", tempdir.c_str(),
                time(NULL), rand());
    }
    std::string dirs = buff;
    mkdirs(dirs.c_str());
    
    time_t tnow1, tnow2;
    tnow1 = time(0);
    std::cout << time(0) << std::endl;
    std::list<std::string> srcfilelist;
    GetAllFile(disk.c_str(), srcfilelist);
    
    split_lock.lock();
    needsplit = srcfilelist.size();
    splited = 0;
    split_lock.unlock();
    
    for(std::list<std::string>::iterator pos = srcfilelist.begin();
            pos != srcfilelist.end(); ++pos)
            {
        std::string filekey = disk + "/" + *pos;
        //SlipTxtFile5<T, Tless>( filekey, dirs, filelist, splipsize);	
        splittxtfilearg arg;
        
        arg.srcfile = filekey;
        arg.dirs = dirs;
        arg.filelist = &filelist;
        arg.splitsize = splipsize;
        
        request_splittxtfilearg.push(arg);
    }

    bt_thread slipthread[cputhread];
    for(int i = 0; i < cputhread; ++i)
    {
        slipthread[i].set_fun(SlipTxtThread);
        slipthread[i].running(NULL);
    }

    while(1)
    {
        bool bresult = false;
        sleep_s(0, 0, 1, 0);
        split_lock.lock();
        std::cout << needsplit << "  " << splited << std::endl;
        if(needsplit == splited)
        {
            bresult = true;
        }

        split_lock.unlock();
        if(bresult == true)
        {
            break;
        }
    }
    std::cout << time(0) << " " << " slipend " << time(0) - tnow1 << std::endl;
    
    tnow2 = time(0);
    
    SumSort5<T, Tless>(destfile, filelist);
    
    std::cout << time(0) << " " << " sumsort " << time(0) - tnow1 << "  "
            << time(0) - tnow2 << std::endl;
}

template<class T1, class T2>
void ShowResult(std::string &filename, std::string destfile = "",
        std::ios::openmode aaa = std::ios_base::out)
{
    std::string outdest = destfile;
    if(outdest == "")
    {
        char buff[1024] = { 0 };
        sprintf(buff, "%s.txt", filename.c_str());
        outdest = buff;
    }
    ofstream outfile(outdest.c_str(), aaa);
    
    ReadProtoFile ta(filename);
    
    T2 tmpt2;
    
    while(1)
    {
        T1 tmpfangzi;
        if(!ta.GetProject(tmpfangzi))
        {
            break;
        }
        else
        {
            tmpt2.template show<T1>(outfile, tmpfangzi);
        }
    }
}

#endif

